﻿using Face8280WebSocketServer.Interface;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Face8280WebSocketServer.DB.Device;
using Face8280WebSocketServer.Model.People;
using Face8280WebSocketServer.DB;
using Face8280WebSocketServer.DB.TimeGroup;
using Newtonsoft.Json.Serialization;
using Face8280WebSocketServer.DB.People;
using System.Collections.Concurrent;
using Face8280WebSocketServer.DTO.FaceDevice;
using Face8280WebSocketServer.Command.Person;
using Face8280WebSocketServer.Utility;
using Face8280WebSocketServer.DTO.FacePeople;

namespace Face8280WebSocketServer.Service
{
    public class CacheService : BaseService, ICacheService
    {
        public const string DeviceCachePrefix = "FC8280TServer:Device:";
        public const string DevicesCacheKey = "FC8280TServer:Devices";
        public const string AccessCachePrefix = "FC8280TServer:Access:";

        IServiceProvider _ServiceProvider;
        private static ConcurrentDictionary<string, FaceDeviceStatus> DeviceList = new ConcurrentDictionary<string, FaceDeviceStatus>();
        private static ConcurrentDictionary<uint, PeopleImageInfo> PeopleImage = new ConcurrentDictionary<uint, PeopleImageInfo>();
        public CacheService(DbContext context, IServiceProvider serviceProvider) : base(context)
        {
            _ServiceProvider = serviceProvider;
        }

        public bool LoadCache()
        {
            DeviceList.Clear();
            var list = Set<FaceDeviceInfo>().ToList();

            foreach (var device in list)
            {
                if (!string.IsNullOrWhiteSpace(device.DeviceSn))
                {
                    var faceStatus = new FaceDeviceStatus().Copy(device);
                    DeviceList.TryAdd(device.DeviceSn, faceStatus);
                }
                else
                {
                    Delete(device);
                }

            }
            var accessList = Set<FacePeopleAccessDetail>().Where(a => a.UploadStatus != 1).ToList();
            var peopleId = accessList.Select(a => a.PeopleID).Distinct().ToArray();
            var peopleList = Set<FacePeopleInfo>().Where(a => peopleId.Contains(a.Id)).ToDictionary(a => a.Id);
            UpdateDeviceAccessTotal1(peopleList, DeviceList.Values.ToList(), accessList);
            return true;
        }
        public void UpdateDeviceAccessTotal1(Dictionary<int, FacePeopleInfo> peopleList, List<FaceDeviceStatus> list, List<FacePeopleAccessDetail> accessList)
        {
            foreach (var faceStatus in list)
            {
                //查找每个设备需要上传的权限
                foreach (var accessDetail in accessList)
                {
                    if (accessDetail.DeviceID == faceStatus.Id)
                    {
                        var people = peopleList[accessDetail.PeopleID];
                        if (accessDetail.UploadStatus == 0)
                        {
                            if (!string.IsNullOrWhiteSpace(people.Photo))
                            {
                                var photoData = FileIOUtility.ReadFaceImage(people.Photo);
                                if (!PeopleImage.ContainsKey(people.Code))
                                {
                                    var photo = new PeopleImageInfo
                                    {
                                        Code = people.Code,
                                        Photo = photoData,
                                        PhotoUrl = people.Photo,
                                        MD5 = MD5Utility.Encrypt(photoData),
                                        Size = photoData.Length

                                    };
                                    PeopleImage.TryAdd(people.Code, photo);
                                }
                                else
                                {
                                    var photo = PeopleImage[people.Code];
                                    var md5 = MD5Utility.Encrypt(photoData);
                                    if (!md5.Equals(photo.MD5))
                                    {
                                        photo.MD5 = md5;
                                        photo.Photo = photoData;
                                        photo.PhotoUrl = people.Photo;
                                        photo.Size = photoData.Length;
                                    }
                                }
                            }
                            faceStatus.AddPeople.Enqueue(InitPerson(accessDetail, people));
                        }
                        if (accessDetail.UploadStatus == 2)
                        {
                            faceStatus.DeletePeople.Add(people.Code);
                        }
                    }
                }
            }
        }

        private Person_DTO InitPerson(FacePeopleAccessDetail accessDetail, FacePeopleInfo facePeople)
        {
            Person_DTO result = new Person_DTO
            {
                Name = facePeople.Name,
                Code = facePeople.Code,
                Group = facePeople.Group,
                Job = facePeople.Job,
                Card = facePeople.Card,
                Pin = facePeople.Pin,
                Start = accessDetail.DevicePassStart.ToDateTimeStr(),
                End = accessDetail.DevicePassEnd.ToDateTimeStr(),
                Times = (short)accessDetail.DevicePassNumber,
                Tp = (byte)accessDetail.TimeGroupID,
                Admin = facePeople.Admin,
                Keep = 0,
                Status = 0,
                UseHol = 0,
                Attachment = new Command.Models.Attachment
                {
                    IdentityId = facePeople.IdentityId,
                    Phone = facePeople.Phone
                }
            };
            return result;
        }

        public bool AddDeviceCache(FaceDeviceInfo oDevice)
        {
            var faceStatus = new FaceDeviceStatus().Copy(oDevice);
            DeviceList.TryAdd(oDevice.DeviceSn, faceStatus);
            return true;
        }

        /// <summary>
        /// 更新设备缓存
        /// </summary>
        /// <param name="oDevice"></param>
        /// <param name="oAccessTotal"></param>
        /// <returns></returns>
        public bool UpdateDeviceCache(FaceDeviceInfo oDevice, (int NewPeople, int DelPeople, int RemoteCount, int AccessTotal) oAccessTotal)
        {
            //var sKey = string.Empty;

            //using (var redis = new RedisHashService())
            //{
            //    ////将已缓存的数据全部删除
            //    //using (var redisset = new RedisSetService())
            //    //{
            //    //    sKey = DevicesCacheKey;

            //    //    redisset.Add(sKey, oDevice.DeviceID);
            //    //}

            //    #region 设备信息
            //    sKey = $"{DeviceCachePrefix}{oDevice.DeviceSn}";
            //    Dictionary<string, string> deviceInfo = new Dictionary<string, string>();
            //    deviceInfo.Add("DeviceID", oDevice.DeviceSn);
            //    deviceInfo.Add("ID", oDevice.Id.ToString());

            ////    deviceInfo.Add("UploadStatus", oDevice.UploadStatus.ToString());
            // //   deviceInfo.Add("UploadStatusTime", oDevice.UploadStatusTime.ToDateTimeStr());
            //    redis.SetRangeInHash(sKey, deviceInfo);

            //    sKey = $"{AccessCachePrefix}{oDevice.DeviceSn}";
            //    //redis.RemoteKey(sKey);
            //    redis.SetEntryInHash(sKey, "AccessTotal", oAccessTotal.AccessTotal.ToString());
            //    redis.SetEntryInHash(sKey, "NewTotal", oAccessTotal.NewPeople.ToString());
            //    redis.SetEntryInHash(sKey, "DeleteTotal", oAccessTotal.DelPeople.ToString());
            //    redis.SetEntryInHash(sKey, "TaskTotal", oAccessTotal.RemoteCount.ToString());

            //    #endregion
            //}

            return true;
        }

        /// <summary>
        /// 根据SN获取设备信息
        /// </summary>
        /// <param name="sn"></param>
        /// <returns></returns>
        public FaceDeviceStatus GetDevice(string sn)
        {
            FaceDeviceStatus oDevice = null;
            string sKey = $"{DeviceCachePrefix}{sn}";
            if (DeviceList.ContainsKey(sn))
                oDevice = DeviceList[sn];
            return oDevice;
        }


        public PeopleImageInfo GetPeopleImage(uint id)
        {
            if (PeopleImage.ContainsKey(id))
                return PeopleImage[id];
            return default;
        }



        public List<FaceDeviceStatus> GetDevices()
        {
            return DeviceList.Values.ToList();


            //using (var redis = new RedisHashService())
            //{
            //    foreach (var sn in stList)
            //    {
            //        string sKey = $"{DeviceCachePrefix}{sn}";
            //        if (redis.ContainsKey(sKey))
            //        {
            //            var oDevice = redis.GetAllEntriesFromHash(sKey).ToJson().FromJson<FaceDeviceInfo>();
            //            oDevices.Add(oDevice);
            //        }
            //    }

        }

        public List<FaceDeviceDetail_PageModel> GetDeviceOnlineStatus(List<FaceDeviceDetail_PageModel> lstDevice)
        {
            foreach (var device in lstDevice)
            {
                if (DeviceList.ContainsKey(device.DeviceID))
                {
                    var oDict = DeviceList[device.DeviceID];
                    device.OnlineTime = oDict.OnlineTime;
                    device.LastKeepaliveTime = oDict.LastKeepaliveTime;
                    device.DoorStatus = oDict.DoorStatus;
                    device.AlarmStatus = oDict.AlarmStatus;
                }
            }
            return lstDevice;
        }



        /// <summary>
        /// 更新设备缓存，仅更新设备信息实体
        /// </summary>
        /// <param name="oDevice"></param>
        /// <param name="oAccessTotal"></param>
        /// <returns></returns>
        public bool UpdateDeviceCache(FaceDeviceInfo oDevice, Action<Dictionary<string, string>, FaceDeviceInfo> updateAction)
        {
            //using (var redis = new RedisHashService())
            //{
            //    #region 设备信息
            //    string sKey = $"{DeviceCachePrefix}{oDevice.DeviceSn}";
            //    Dictionary<string, string> deviceInfo = new Dictionary<string, string>();
            //    updateAction(deviceInfo, oDevice);

            //    var sDels = new List<string>(deviceInfo.Count);
            //    foreach (var item in deviceInfo)
            //    {
            //        if (string.IsNullOrEmpty(item.Value))
            //        {
            //            redis.RemoveEntryFromHash(sKey, item.Key);
            //            sDels.Add(item.Key);
            //        }
            //    }
            //    sDels.ForEach(x => deviceInfo.Remove(x));

            //    redis.SetRangeInHash(sKey, deviceInfo);
            //    #endregion
            //}

            return true;
        }

        public bool ReplaceDeviceSN(string sOldSN, string sNewSN)
        {
            //using (var redis = new RedisHashService())
            //{
            //    #region 设备信息
            //    string sKey = $"{DeviceCachePrefix}{sOldSN}";
            //    if (redis.ContainsKey(sKey))
            //    {
            //        var deviceInfo = redis.GetAllEntriesFromHash(sKey);
            //        redis.RemoteKey(sKey);

            //        sKey = $"{DeviceCachePrefix}{sNewSN}";
            //        deviceInfo["DeviceID"] = sNewSN;
            //        redis.SetRangeInHash(sKey, deviceInfo);
            //    }


            //    sKey = $"{AccessCachePrefix}{sOldSN}";
            //    if (redis.ContainsKey(sKey))
            //    {
            //        var deviceInfo = redis.GetAllEntriesFromHash(sKey);
            //        redis.RemoteKey(sKey);

            //        sKey = $"{AccessCachePrefix}{sNewSN}";
            //        redis.SetRangeInHash(sKey, deviceInfo);
            //    }


            //    #endregion
            //}

            //using (var redisset = new RedisSetService())
            //{
            //    string sKey = DevicesCacheKey;

            //    redisset.RemoveItemFromSet(sKey, sOldSN);
            //    redisset.Add(sKey, sNewSN);

            //}


            return true;
        }



        /// <summary>
        /// 删除设备缓存
        /// </summary>
        /// <param name="oDevices"></param>
        /// <returns></returns>
        public bool DeleteDeviceCache(string sn)
        {
            DeviceList.TryRemove(sn, out _);
            return true;
        }

        public (int NewPeople, int DelPeople, int AccessTotal, int RemoteCount, int EmptyPeople) GetTaskDetail(string sn)
        {
            (int NewPeople, int DelPeople, int AccessTotal, int RemoteCount, int EmptyPeople) ret = (0, 0, 0, 0, 0);

            //using (var redis = new RedisHashService())
            //{
            //    string sKey = $"{AccessCachePrefix}{sn}";
            //    if (redis.ContainsKey(sKey))
            //    {
            //        var oValues = redis.GetAllEntriesFromHash(sKey);
            //        try
            //        {
            //            ret.AccessTotal = int.Parse(oValues["AccessTotal"]);
            //            ret.NewPeople = int.Parse(oValues["NewTotal"]);
            //            ret.DelPeople = int.Parse(oValues["DeleteTotal"]);
            //            ret.RemoteCount = int.Parse(oValues["TaskTotal"]);
            //            ret.EmptyPeople = int.Parse(oValues["EmptyPeople"]);
            //        }
            //        catch (Exception)
            //        {


            //        }
            //    }


            //}
            return ret;
        }


        public void UpdateDeviceRemoteCache(Dictionary<string, int> oTotals)
        {

            //using (var redis = new RedisHashService())
            //{

            //    foreach (var totalDetail in oTotals)
            //    {
            //        var sKey = $"{AccessCachePrefix}{totalDetail.Key}";
            //        redis.SetEntryInHash(sKey, "TaskTotal", totalDetail.Value.ToString());
            //    }
            //}

        }

        public void UpdateDeviceAccessCache(Dictionary<string, (int NewPeople, int DelPeople, int AccessTotal)> oTotals)
        {
            //using (var redis = new RedisHashService())
            //{
            //    foreach (var sn in oTotals)
            //    {
            //        var oTotal = sn.Value;

            //        string sKey = $"{AccessCachePrefix}{sn.Key}";
            //        redis.SetEntryInHash(sKey, "AccessTotal", oTotal.AccessTotal.ToString());
            //        redis.SetEntryInHash(sKey, "NewTotal", oTotal.NewPeople.ToString());
            //        redis.SetEntryInHash(sKey, "DeleteTotal", oTotal.DelPeople.ToString());
            //    }
            //}
        }


        public int GetNewPeopleTotal(string deviceSN)
        {
            int rst = 0;
            //using (var redis = new RedisHashService())
            //{
            //    string sKey = $"{AccessCachePrefix}{deviceSN}";
            //    if (redis.ContainsKey(sKey))
            //    {
            //        //rst.Total
            //        int.TryParse(redis.GetValueFromHash(sKey, "NewTotal"), out rst);
            //    }
            //}
            return rst;
        }

        public FaceDeviceInfo GetDeviceDetail(string sn)
        {
            FaceDeviceInfo oDevice = null;
            string sKey = $"{DeviceCachePrefix}{sn}";

            //using (var redis = new RedisHashService())
            //{
            //    if (redis.ContainsKey(sKey))
            //    {
            //        oDevice = redis.GetAllEntriesFromHash(sKey).ToJson().FromJson<FaceDeviceInfo>();
            //    }
            //    else
            //    {
            //        //去查数据库
            //        oDevice = null;
            //    }
            return oDevice;
            //}

        }


        public void SaveDeviceReadPeopleCodeList(string sSN, IEnumerable<long> PeopleIDs)
        {
            //using (var redis = new RedisHashService())
            //{
            //    string sKey = $"{AccessCachePrefix}{sSN}";
            //    redis.SetEntryInHash(sKey, "ReadPeopleIDList", string.Join(",", PeopleIDs));
            //}
        }


        (List<long> Codes, int DoorID) ICacheService.GetDeviceReadPeopleCodeList(string sSN)
        {
            (List<long> Codes, int DoorID) rst = (null, 0);
            //using (var redis = new RedisHashService())
            //{
            //    string sKey = $"{AccessCachePrefix}{sSN}";
            //    string sCodes = redis.GetValueFromHash(sKey, "ReadPeopleIDList");
            //    if (!string.IsNullOrWhiteSpace(sCodes))
            //        rst.Codes = sCodes.Split(",").Select(x => long.Parse(x)).ToList();
            //    //string[] sCodeArray = sCodes.Split(",");

            //    sKey = $"{DeviceCachePrefix}{sSN}";
            //    string sDoorID = redis.GetValueFromHash(sKey, "ID");
            //    int.TryParse(sDoorID, out rst.DoorID);
            //}

            return rst;
        }

        public void DeleteDeviceReadPeopleCodeList(string sSN)
        {
            //using (var redis = new RedisHashService())
            //{
            //    string sKey = $"{AccessCachePrefix}{sSN}";
            //    redis.SetEntryInHash(sKey, "ReadPeopleIDList", "");
            //}
        }

        public void SaveDeviceDeletePeopleCodeList(string sSN, IEnumerable<long> PeopleCodes)
        {
            //using (var redis = new RedisHashService())
            //{
            //    string sKey = $"{AccessCachePrefix}{sSN}";
            //    redis.SetEntryInHash(sKey, "DeletePeopleIDList", string.Join(",", PeopleCodes));
            //}
        }

        public (List<long> Codes, int DoorID) GetDeviceDeletePeopleCodeList(string sSN)
        {
            (List<long> Codes, int DoorID) rst = (null, 0);
            //using (var redis = new RedisHashService())
            //{
            //    string sKey = $"{AccessCachePrefix}{sSN}";
            //    string sCodes = redis.GetValueFromHash(sKey, "DeletePeopleIDList");
            //    if (!string.IsNullOrWhiteSpace(sCodes))
            //        rst.Codes = sCodes.Split(",").Select(x => long.Parse(x)).ToList();
            //    //string[] sCodeArray = sCodes.Split(",");

            //    sKey = $"{DeviceCachePrefix}{sSN}";
            //    string sDoorID = redis.GetValueFromHash(sKey, "ID");
            //    int.TryParse(sDoorID, out rst.DoorID);
            //}

            return rst;
        }

        public void DeleteDeviceDeletePeopleCodeList(string SN)
        {
            //using (var redis = new RedisHashService())
            //{
            //    string sKey = $"{AccessCachePrefix}{SN}";
            //    redis.SetEntryInHash(sKey, "DeletePeopleIDList", "");
            //}
        }

        public void UpdateDeviceEmptyPeopleCache(Dictionary<string, int> dic)
        {
            //using (var redis = new RedisHashService())
            //{

            //    foreach (var totalDetail in dic)
            //    {
            //        var sKey = $"{AccessCachePrefix}{totalDetail.Key}";
            //        redis.SetEntryInHash(sKey, "EmptyPeople", totalDetail.Value.ToString());
            //    }
            //}
        }

        public void UpdateDeviceAccessCache(string sn, Action<Dictionary<string, string>> actionCallblack)
        {
            //using (var redis = new RedisHashService())
            //{
            //    var sKey = $"{AccessCachePrefix}{sn}";
            //    var dic = new Dictionary<string, string>();
            //    actionCallblack(dic);
            //    redis.SetRangeInHash(sKey, dic);

            //}
        }

        public bool GetDeviceCacheHashValue(string sn, HashSet<string> keys, Dictionary<string, string> dic)
        {
            //using (var redis = new RedisHashService())
            //{
            //    var sKey = $"{DeviceCachePrefix}{sn}";
            //    var keysArr = keys.ToArray();
            //    var sValues = redis.GetValuesFromHash(sKey, keysArr);
            //    for (int i = 0; i < keysArr.Length; i++)
            //    {
            //        sKey = keysArr[i];
            //        dic.Add(sKey, sValues[i]);
            //    }
            //}
            return true;
        }
    }
}
